Newsgroups: comp.sources.misc
organization: Cetia, Toulon, France
keywords: SCCS, sources
subject: v07i123: functions to maintain SCCS'ed source trees
from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
Reply-To: chris@cetia.UUCP (Chris Bertin)

Posting-number: Volume 7, Issue 123
Submitted-by: chris@cetia.UUCP (Chris Bertin)
Archive-name: sccs.sh

This is a file I keep in my home directory under the name '.shrc.sccs'. It
contains quite a few functions that I use to manage SCCS, to do source tree
comparisons, etc... This stuff has evolved over the years and some of the
functions have gotten quite large; in fact, several of them should probably
be turned into separate shell scripts. All these functions assume that the
SCCS files are kept in an 'SCCS' directory. If you have the BSD 'sccs' command,
several of these functions will lose some of their usefulness. I have never
bothered with 'sccs' because I started to use these functions before the 'sccs'
command came out.

----------------------------------- cut here ---------------------------------
##
## ex:set sw=4:		# set shiftwidth to 4 when editing this file
##
##
##	SCCS functions
##
##					Chris Bertin
##
##

Company=YOUR_SITE		# Used for header functions

# Files matching the following patterns will be skipped by 'recdiff'
RECSKIP="tags *.out llib*.ln lib.*"

# admin files
adm()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: adm files" >&2
	return 1
    }
    [ -d SCCS ] || {
	echo "Creating SCCS directory"
	mkdir SCCS || return 1
    }
    for AFile do
	admin -i${AFile} SCCS/s.${AFile} && {
	     rm -f ${AFile}
	     get SCCS/s.${AFile}
	}
	shift
    done
    unset AFile
}

# admin all files in the current directory
adminall()
{
    [ -f *.mk ] && AFile=`echo *.mk` || {
	    [ -f Makefile ] && AFile=Makefile || {
		    [ -f makefile ] && AFile=makefile
	    }
    }
    [ -f "${AFile}" ] && {
	echo "Warning: doing a 'make clobber'"
	sleep 5
	make -f ${AFile} clobber
    }
    adm `ls | grep -v SCCS`
    ls -l *
}

# handle pending files in directory trees (default '.') using delall (see below)
recdel()
{
    [ ${#} -gt 0 ] && List="$*" ||  List=`pwd`
    CurDir=`pwd`
    trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3
    for Tree in ${List}; do
	echo "Doing ${Tree}"
	cd ${Tree} || continue
	for Dir in `find . -type d ! -name SCCS -print | sed "s/^\.\///"` ; do
	    cd ${Dir} && delall || { cd ${CurDir}; trap 1 2 3; return 1; }
	    cd ${CurDir} && cd ${Tree}
	done
	cd ${CurDir}
    done
    unset CurDir Tree Dir List
    trap 1 2 3
}

# handle all pending files in the current directory (delta or unget or nothing)
delall()
{
    [ ${#} -ne 0 ] && {
	echo "Usage: delall" >&2
	return 1
    }
    [ -z "`pend`" ] && {
	echo "Nothing pending in `pwd`" >&2
	return 0
    }
    for DLFile in `pend` ; do
	echo ">> `pwd`/${DLFile}"
	xdiff ${DLFile}
	[ ! -t 1 ] && { echo "-----------------------------"; continue; }
	while : ; do
	    echo "${DLFile}: [dacpqrsuv] (or '?' for help): \c"
	    read ANSWER < /dev/tty
	    # Note that there is no 'shift' here. They are handled by the
	    # functions called in each case. This is a major uglyness in 'sh'.
	    case "${ANSWER}" in
	    c*|C*)
		CoMMent="`echo ${ANSWER} | sed 's/[a-zA-Z]* //'`"
		echo "New comment is \"${CoMMent}\""
		continue
		;;
	    a*|A*)
		echo "Autodelta with comment: \"${CoMMent}\""
		sleep 1
		chkpfile ${DLFile} || continue
		delta -y"${CoMMent}" SCCS/s.${DLFile}
		getn ${DLFile}
		;;
	    d*|D*)
		del ${DLFile}
		;;
	    p*|P*)
		echo "Current autocomment is: \"${CoMMent}\"" 
		continue
		;;
	    u*|U*)
		ung ${DLFile}
		;;
	    r*|R*)
		xdiff ${DLFile}
		continue
		;;
	    v*|V*)
		vi ${DLFile}
		xdiff ${DLFile}
		continue
		;;
	    s*|S*)
		${SHELL:-/bin/sh}
		echo "exited"
		continue
		;;
	    q*|Q*)
		return 1
		;;
	    "")
		echo "${DLFile} unchanged..."
		;;
	    ?*|*)
		echo "Usage:\t\"c new auto comment\" (enter new comment)" >&2
		echo "\t\"a\" (auto delta with previous auto comment)" >&2
		echo "\t\"d\" (delta file manually)" >&2
		echo "\t\"p\" (print autocomment)" >&2
		echo "\t\"q\" (quit)" >&2
		echo "\t\"r\" (redo)" >&2
		echo "\t\"s\" (sub-shell)" >&2
		echo "\t\"u\" (unget file)" >&2
		echo "\t\"v\" (vi file)" >&2
		echo "\t\"\"  (do nothing)" >&2
		continue
		;;
	    esac
	    break
	done
    done
    return 0
}

# check if there is an 'SCCS' directory. Args are passed because 'sh' doesn't
# stack arguments to functions.
chkSCCSdir()
{
    [ -d SCCS ] || {
	echo "No SCCS directory" >&2
	return 1
    }
    return 0
}

# check if file is SCCS'ed.
chkSCCSfile()
{
    [ -f SCCS/s.${1} ] && return 0
    echo "${1} not SCCS'ed" >&2
    return 1
}

# delta files
del()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: del files" >&2
	return 1
    }
    for DFile do
	chkpfile ${DFile} || continue
	delta SCCS/s.${DFile} && get SCCS/s.${DFile}
	shift
    done
    unset DFile
}

# check whether p file is valid
chkpfile()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: chkpfile files" >&2
	return 1
    }
    [ $# -ne 1 ] && { echo "Arg count"; return 1; }
    [ -r SCCS/p.${1} ] || { echo "${1} not pending"; return 1; }
    WhoAmI=`whoami`
    WhoIsIt="`awk '{print $3}' < SCCS/p.${1}`"
    [ "${WhoAmI}" != "${WhoIsIt}" ] && {
	echo "You didn't get ${1} -- (`cat SCCS/p.${1}`)"
	if [ -t 1 ]; then
	    echo "Fix it? \c"
	    read ANSWER < /dev/tty
	else
	    ANSWER="${DEFCHKP}"
	fi
	case "${ANSWER}" in
	y*|Y*)
	    echo "s/${WhoIsIt}/${WhoAmI}/\nw\nq" | ed - SCCS/p.${1}
	    [ ${?} -ne 0 ] && {
		echo "Can't fix SCCS/p.${1} -- Sorry";
		return 1;
	    }
	    [ -t 1 ] || echo "Pfile fixed"
	    return 0
	    ;;
	*)
	    return 1
	    ;;
	esac
    }
    return 0
}

# get an SCCS file in edit mode
gete()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: gete files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for GEFile do
	chkSCCSfile ${GEFile} && get -e SCCS/s.${GEFile}
	shift
    done
    unset GEFile
}

# get an SCCS file without editing
getn()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: getn files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for GNFile do
	chkSCCSfile ${GNFile} && get SCCS/s.${GNFile}
	shift
    done
    unset GNFile
}

# get an SCCS file into standard output
getp()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: getp files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for GPFile do
	chkSCCSfile ${GPFile} && get -p SCCS/s.${GPFile}
	shift
    done
    unset GPFile
}

# get given version of an SCCS file into standard output
getv()
{
    [ ${#} -ne 2 ] && {
	echo "Usage: getv version file" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    VeRs=${1}
    shift
    chkSCCSfile ${1} && get -p -r${VeRs} SCCS/s.${1}
    unset VeRs
}

# unget SCCS files that have been get'ed but not modified (in current directory)
cleanget()
{
    [ ${#} -ne 0 ] && {
	echo "Usage: cleanget" >&2
	return 1
    }
    CurDir=`pwd`
    trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3
    find . -type f -name "p.*" -print | while read CGfile; do
	BaseName=`basename ${CGfile} | sed "s/p.//"`
	cd `dirname ${CGfile}`/.. || continue
	echo ${BaseName}: pending in directory `pwd`
	get -k -p SCCS/s.${BaseName} 2>&- | ${DIFF:-diff} - ${BaseName} >&- 2>&- && {
	    echo No differences for SCCS/s.${BaseName}
	    CurDate=`/src/uts/m68k/bin/curdate ${BaseName}`
	    chkpfile ${BaseName} || continue
	    ung ${BaseName}
	    touch -m ${CurDate} ${BaseName}
	}
	cd ${CurDir}
    done
    unset CurDir CGfile CurDate BaseName
    trap 1 2 3
}

# SCCS history for SCCS files
hist()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: hist files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for HFile do
	chkSCCSfile ${HFile} && prs -e \
	    -d'Delta for :M:: -- :I: --, Date: :D:\nUpdate: :C:' SCCS/s.${HFile}
	shift
    done
    unset HFile
}

# examine SCCS files
m()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: m files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for MFile do
	chkSCCSfile ${MFile} && get -s -p SCCS/s.${MFile} | ${PAGER:-pg}
	shift
    done
    unset MFile
}

# show which SCCS files are pending. Optionnal args limit the name expansion
pend()
{
    chkSCCSdir $* || return 1
    [ -f SCCS/p.* ] && echo `ls SCCS/p.*${1} 2>&- | sed "s/^SCCS\/p.//"`
}

# show all pending files in the given directory trees (default '.')
pendall()
{
    [ ${#} -gt 0 ] && List="$*" ||  List=.
    for Tree in ${List}; do
	find ${Tree} -type f -name 'p.*' -print | \
		sed -e 's/^\.\///' -e 's/SCCS\/p\.//'
    done
    unset Tree List
}

# add a SCCS header to the given C files
shead()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: shead files" >&2
	return 1
    }
    for SFile do
	echo '1i\n#ifndef lint\nstatic char ID[] = "%W% ${Company} %E%";\n#endif lint\n.\nw\nq' | ed - ${SFile}
    done
    unset SFile
}

# add a SCCS header to the given header files
shhead()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: shhead files" >&2
	return 1
    }
    for SHFile do
	echo '1i\n/* %W% ${Company} %E% */\n.\nw\nq' | ed - ${SHFile}
    done
    unset SHFile
}

# add a SCCS header to the given FORTRAN files
sfhead()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: sfhead files" >&2
	return 1
    }
    for SFFile do
	echo '1i\n* %W% ${Company} %Z%\n.\nw\nq' | ed - ${SFFile}
    done
    unset SFFile
}

# add a SCCS header to the given SHELL (or MAKEFILE) files
sshead() { smhead $*; }
smhead()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: smhead files" >&2
	return 1
    }
    for MHFile do
	echo '1i\n# %W% ${Company} %Z%\nw\nq' | ed - ${MHFile}
    done
    unset MHFile
}

# unget files
ung()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: ung files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for UFile do
	chkSCCSfile ${UFile} && chkpfile ${UFile} && \
	    unget SCCS/s.${UFile} && get SCCS/s.${UFile}
	shift
    done
    unset UFile
}

# unget files without reextracting them
ungn()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: ungn files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for UNFile do
	chkSCCSfile ${UNFile} && chkpfile ${UNFile} && unget SCCS/s.${UNFile}
	shift
    done
    unset UNFile
}

# show SCCS versions
vs()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: vs files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for VFile do
	chkSCCSfile ${VFile} && prs -d"Current delta for :M:: -- :I: --, Date: :D:\nLast update: :C:" SCCS/s.${VFile}
	shift
    done
    unset VFile
}

# show SCCS versions of a full directory
vss()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: vss sccs_directory" >&2
	return 1
    }
    prs -d"Current delta for :M:: -- :I: --, Date: :D:\nLast update: :C:" $1
}

# diff an SCCS file and its extracted counterpart
xdiff()
{
    [ ${#} -eq 0 ] && {
	echo "Usage: xdiff files" >&2
	return 1
    }
    chkSCCSdir $* || return 1
    for XFile do
	chkSCCSfile ${XFile} || continue
	[ ! -f ${XFile} ] && {
	     ls ${XFile}
	     continue
	}
	vs ${XFile} && get -p SCCS/s.${XFile} | ${DIFF:-diff} - ${XFile} 2>&1 | ${PAGER:-pg}
    done
    unset XFile
}

## sccsdiff between 2 versions
scdiff()
{
    [ ${#} -lt 3 ] && {
	echo "Usage: scdiff rel1 rel2 files" >&2
	return 1
    }
    R1=$1; shift
    R2=$1; shift
    chkSCCSdir $* || return 1
    for SFiLE do
	chkSCCSfile ${SFiLE} || continue
	sccsdiff -r${R1} -r${R2} SCCS/s.${SFiLE} | ${PAGER:-pg}
    done
    unset R1 R2 SFiLE
}

# recursive difference between 2 trees, using diffall (See below)
recdiff()
{
    Skip=
    Flag=
    for Opt in "$@"; do
	case ${Opt} in
	-F|-f) Flag="${Flag} -f"
	    [ ${Opt} = "-f" ] && Fopt="-o -type l"; shift
	    ;;
	-o) Flag="${Flag} -o"; shift
	    ;;
	-s) Skip="! -name SCCS" ;shift
	    ;;
	*)  break
	    ;;
    	esac
    done
    [ \( ${#} -eq 1 -a ${1} = '-' \) -o ${#} -eq 2 ] && {
	:
    } || {
	echo "Usage:\trecdiff [-f] [-F] [-o] [-s] ['-' or dir1] dir2" >&2
	echo "\t-f: follow symbolic links in destination" >&2
	echo "\t-F: follow symbolic links both in source and destination" >&2
	echo "\t-o: compare non ascii files" >&2
	echo "\t-s: skip SCCS directories" >&2
	echo "\t- : If first argument is '-', do recursive SCCS diffs" >&2
	return 1
    }
    BaseDir="."
    Arg1=${1}
    Arg2=${2}
    if [ ${Arg1} = "-" ]; then
	Skip="! -name SCCS"
	[ ${#} = 1 ] && set - "." || BaseDir=${2}
	Sdiff=true
	shift
    else
	Sdiff=false
    fi
    CurDir=`pwd`
    for Dir do
	[ ! -d ${Dir} ] && {
	    echo "${Dir}: not a directory"
	    unset Dir
	    return 1
	}
    done
    if [ ${Sdiff} = false ]; then
	cd ${Arg2} || return 1
	Dest=`pwd`
	cd ${CurDir} || return 1
    fi
    if [ ${Sdiff} = false ]; then
	cd ${Arg1} || return 1
    fi
    trap "cd ${CurDir}; echo '...Aborted'; trap 1 2 3; return -1 >&- 2>&-" 1 2 3

    find ${BaseDir} ${Skip} \( -type d ${Fopt} \) -print | sed "s/^\.\///" | \
    while read Dir; do
	[ -d ${Dir} ] || continue
	echo "------ Directory: ${CurDir}/${Dir} ------"
	cd ${Dir} || continue
	if [ ${Sdiff} = true ]; then
	    if [ -d SCCS ]; then
		Pending="`pend`"
		if [ "${Pending}" != "" ]; then
		    diffall ${Flag} - ${Pending} || break
		fi
	    fi
	    cd ${CurDir}
	    continue
	fi
	if [ ! -d ${Dest}/${Dir} ]; then
	    diffall ${Flag} ${Dir} ${Dest}	# for error handling
	else
	    List=""
	    for F in `ls -a`; do
		[ -z "${RECSKIP}" ] || {
		    for FF in `echo ${RECSKIP}` ; do
			[ ${FF} = ${F} ] && {
			    echo "===== ${F} ===== Skipped"
			    continue 2
			}
		    done
		}
		[ -f ${F} ] && List="${List} ${F}"
	    done
	    [ -z "${List}" ] || diffall ${Flag} ${List} ${Dest}/${Dir} || break
	fi
	cd ${CurDir}
	cd ${Arg1}
    done
    cd ${CurDir}
    unset Arg1 Arg2 CurDir Skip Dir Dest Flag Fopt F List Opt Pending Sdiff
    trap 1 2 3
}

# diff a series of files with their SCCS counterpart or another directory
diffall()
{
    Dusage() {
	echo "Usage:\tdiffall [-f] [-o] ['-' or files] [directory]" >&2
	echo "\t-f: follow symbolic links" >&2
	echo "\t-o: compare non ascii files" >&2
    }
    Nodiff() { REDO=0; echo "$* No differences"; }
    Follow=false
    Dotos=false
    for Opt in "$@"; do
	case ${Opt} in
	-f) Follow=true; shift
	    ;;
	-o) Dotos=true; shift
	    ;;
	*)  break
	    ;;
    	esac
    done
    [ "$1" = "" ] && { Dusage; return 1; }
    if [ "$1" = "-" ]; then
	XdIfF=true
	DiR="."
	shift
	chkSCCSdir $*
    else
	Args=$*
	XdIfF=false
	DiR=`echo $* | sed "s/.* //"`
	[ ! -d "${DiR}" ] && {
	    echo "${DiR}: not a directory" >&2
	    Dusage
	    return 1
	}
	ls ${DiR} > /tmp/di$$
	More=`ls | ${DIFF:-diff} - /tmp/di$$ | grep "^> " | sed "s/^> //"`
	rm -f /tmp/di$$
	[ -z "${More}" ] || echo "\nWARNING: `echo ${More}` only in ${DiR}\n"
	set ${Args}
	unset More Args
    fi
    Dcheckread() {
	for FIle do
	    [ -d ${FIle} -o -c ${FIle} -o -b ${FIle} -o ! -r ${FIle} ] && {
		echo "skipping `file ${FIle}`"
		unset FIle
		return 1
	    }
	done
	unset FIle
	return 0
    }
    for FiLe do
	[ "${FiLe}" = "${DiR}" ] && break
	REDO=1
	while [ ${REDO} -gt 0 ] ; do
	    [ ${REDO} -eq 1 ] && echo  "====== ${FiLe} ===== \c"
	    if [ ${REDO} -eq 2 ]; then
		: do nothing. We got here because of wrong answer below
	    elif [ "${XdIfF}" = "true" ] ; then
		[ -d ${FiLe} ] && {
		    echo "${FiLe}: Directory"
		    REDO=0
		    continue
		}
		if Dcheckread ${FiLe} SCCS/s.${FiLe} ; then
		    get -p -s SCCS/s.${FiLe} 2>&- | ${CMP:-cmp} - ${FiLe} 2>&1 && {
			Nodiff
			continue
		    }
		    get -p -s SCCS/s.${FiLe}| ${DIFF:-diff} - ${FiLe} | \
		      ${PAGER:-pg}
		fi
	    else
		if [ ${Follow} = false -a \
		     `ls -l ${FiLe} 2>&- | grep -c " -> "` -eq 1 ] ; then
		    echo "${FiLe}: Symbolic link\c"
		    if [ "`ls -d ${DiR}/${FiLe} 2>&-`" != "${DiR}/${FiLe}" ]; then
			echo "s differ: ${DiR}/${FiLe} doesn't exist"
		    elif [ `ls -l ${DiR}/${FiLe} | grep -c " -> "` -eq 1 ]; then
			ls -l ${FiLe} 2>&- | sed "s/.* -> //" > /tmp/dall.$$
			ls -l ${DiR}/${FiLe} 2>&- | sed "s/.* -> //" | \
			    ${DIFF:-diff} - /tmp/dall.$$ >&- 2>&-
			[ ${?} = 0 ] && {
			    rm -f /tmp/dall.$$
			    Nodiff "s,"
			    continue
			} || {
			    rm -f /tmp/dall.$$
			    echo "s differ:"
			    ls -l ${FiLe} ${DiR}/${FiLe}
			}
		    else
			echo " but ${FiLe} differ: `file ${DiR}/${FiLe}`"
		    fi
		else
		    if Dcheckread ${FiLe} ${DiR}/${FiLe}; then
			if file ${FiLe} | \
			  egrep " executable| archive| object|	data" >&-; then
			    echo "`file ${FiLe} | \
				sed 's/[	 ][	 ]*/ /g'` -> \c"
			    [ ${Dotos} = false ] && {
				echo "Ignored"
				REDO=0
				continue
			    }
			    ${CMP:-cmp} ${FiLe} ${DiR}/${FiLe} 2>&1 && {
				Nodiff
				continue
			    }
			else
			    ${CMP:-cmp} ${FiLe} ${DiR}/`basename ${FiLe}` 2>&1 && {
				Nodiff
				continue
			    }
			    ${DIFF:-diff} ${FiLe} ${DiR} | ${PAGER:-pg}
			fi
		    fi
		fi
	    fi
	    [ ! -t 1 ] && { REDO=0; continue; }
	    echo "====== ${FiLe} done ===== Hit return to continue: \c"
	    REDO=0
	    read a < /dev/tty
	    [ -z "${a}" ] && continue
	    case ${a} in
	    vi|e|v)	REDO=1 ; vi ${FiLe} ;;
	    mod)	REDO=2 ; echo "cpio: -m option will be used"; Dopt=m ;;
	    nomod)	REDO=2 ; echo "cpio: no -m option"; Dopt="" ;;
	    redo|r)	REDO=1 ;;
	    quit|q)	return 1 ;;
	    put|PUT)	REDO=1
			[ ${XdIfF} = true ] && {
			    echo "Cannot put with '-' option" >&2
			    REDO=2
			    continue;
			}
			if [ ${a} = PUT ]; then
			    rm -r ${DiR}/${FiLe} || {
				REDO=2
				continue
			    }
			fi
			if [ -f ${FiLe} ] ; then
			    find ${FiLe} -print | cpio -pduvv${Dopt} ${DiR}
			elif [ -d ../${FiLe} ] ; then
			    mkdir ${DiR}/${FiLe} || {
				REDO=2
				continue
			    }
			    cd ..; find ${FiLe} -print | cpio -pduvv${Dopt} ${DiR}
			else
			    echo "case not handled"
			    REDO=2
			fi
			;;
	    get|GET)	REDO=1
			if [ ${XdIfF} = true ]; then
			    if [ -f SCCS/p.${FiLe} ]; then
				if [ ${a} = GET ]; then
				    ung ${FiLe} || REDO=2
				else
				    echo "File is out being edited. Use GET to overwrite"
				    REDO=2
				fi
			    fi
			    [ ${REDO} -gt 0 ] && continue
			    get SCCS/s.${FiLe} || REDO=2
			else
			    [ ${a} = GET ] && rm -rf ${FiLe}
			    export Dopt
			    ( Here=`pwd`; chdir ${DiR} && \
			      find ${FiLe} -print | cpio -pduvv${Dopt} ${Here} )
			fi
			;;
	    sh)		${SHELL:-/bin/sh}
			REDO=2 ;;
	    '?'|*)	echo "Usage:\tvi|e|v:\tedit local file" >&2
			echo "\tr|redo:\tredo file" >&2
			echo "\tq|quit:\tquit" >&2
			echo "\tput:\tcopy local file to remote file" >&2
			echo "\tPUT:\tsame but forcibly" >&2
			echo "\t[no]mod:\t[don't] use -m option for put/get" >&2
			echo "\tget:\tcopy remote file to local file (or get SCCS file)" >&2
			echo "\tGET:\tsame but forcibly" >&2
			echo "\tsh:\tsub-shell" >&2
			echo "\t'?':\thelp" >&2
			REDO=2 ;;
	    esac
	    unset a
	done
    done
    unset FiLe Opt Follow Skip Dotos Follow REDO More Dopt Nodiff Dusage
    return 0
}
----------------------------------- cut here ---------------------------------
-- 
Chris Bertin	| -- CETIA -- 150, Av Marcelin Berthelot, Z.I. Toulon-Est
+33(94)212005	| 83088 Toulon Cedex, France
		| inria!cetia!chris


